package pub.gll.onepeas.libbase.track.ui

import android.content.Context
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.View
import android.widget.FrameLayout
import pub.gll.onepeas.libbase.track.util.ViewExposureLog
import pub.gll.onepeas.libbase.track.constants.ViewExposureConstants.TRIGGER_VIEW_CHANGED
import pub.gll.onepeas.libbase.track.constants.ViewExposureConstants.TRIGGER_WINDOW_CHANGED
import pub.gll.onepeas.libbase.track.manager.KKExposurePageManager
import pub.gll.onepeas.libbase.track.model.ExposureModel
import java.util.*
import kotlin.math.abs

/**
 * <pre>
 * @author : whg
 * @e-mail : guanhuawei@kkworld.com
 * @time   : 2021/6/17 10:37
 * @desc   :
 * 基于现有问题和公共事件重新设计的view全曝光埋点方案
 * https://wiki.quickcan.com/pages/viewpage.action?pageId=397084181
 * @version: 1.0
</pre> *
 */
class KKTrackerExposureLayout : FrameLayout, GestureDetector.OnGestureListener {

    private var isHasLayout: Boolean = true
    private var mOriX = 0f
    private var mOriY = 0f
    private var mGestureDetector: GestureDetector? = null

    /**
     * 当前页面，上次所有可见的view
     */
    val lastVisibleViewMap: MutableMap<Any, ExposureModel> = WeakHashMap()

    /**
     * 上次layout的时间
     */
    private var lastOnLayoutSystemTimeMillis: Long = 0
    private var lastOnWindowFocusChangedSystemTimeMillis: Long = 0
    private var lastOnVisibilityChangedSystemTimeMillis: Long = 0


    constructor(context: Context) : super(context) {
        mGestureDetector = GestureDetector(context, this)
        KKExposurePageManager.setLayoutExposureManager(this)
    }

    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)

    /**
     * 时机1:开始滑动
     * @param ev MotionEvent
     * @return Boolean
     */
    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        mGestureDetector!!.onTouchEvent(ev)
        when (ev.action) {
            MotionEvent.ACTION_DOWN -> {
                mOriX = ev.x
                mOriY = ev.y
            }
            MotionEvent.ACTION_MOVE ->
                //判断滑动距离超过阈值时，Activity判断当前哪些View可见并跟上次缓存相比较。 每次曝光差异的View
                if (abs(ev.x - mOriX) > CLICK_LIMIT || abs(ev.y - mOriY) > CLICK_LIMIT) {
                    isHasLayout = false
                    KKExposurePageManager.getExposureManager(this)?.triggerViewCalculate(
                        TRIGGER_VIEW_CHANGED,
                        this,
                        isVisible = true,
                        clearAll = false,
                        lastVisibleViewMap = lastVisibleViewMap
                    )
                }
            MotionEvent.ACTION_UP -> {
            }
        }
        return super.dispatchTouchEvent(ev)
    }

    /**
     * view的状态改变都会触发
     *
     * @param changed
     * @param left
     * @param top
     * @param right
     * @param bottom
     */
    override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
        val time = System.currentTimeMillis()
        if (time - lastOnLayoutSystemTimeMillis > 1000) {
            lastOnLayoutSystemTimeMillis = time
            isHasLayout = true
            // KKExposureManager.getInstance().traverseViewTree(this, mReuseLayoutHook)
            //800ms的延迟，在页面的view产生时机变化时，onLayout的已经走了，但是页面的数据还没来得及刷新，延迟做容错
            postDelay(800) {
                ViewExposureLog.d("==== onLayout $changed")
                KKExposurePageManager.getExposureManager(this)?.triggerViewCalculate(
                    TRIGGER_VIEW_CHANGED,
                    this,
                    isVisible = true,
                    clearAll = false,
                    lastVisibleViewMap = lastVisibleViewMap
                )
                isHasLayout = false
            }
        }

        super.onLayout(changed, left, top, right, bottom)
    }

    override fun onDown(motionEvent: MotionEvent): Boolean {
        return false
    }

    override fun onShowPress(motionEvent: MotionEvent) {}

    override fun onSingleTapUp(motionEvent: MotionEvent): Boolean {
        return false
    }

    override fun onLongPress(motionEvent: MotionEvent) {}

    override fun onScroll(
        motionEvent: MotionEvent,
        motionEvent1: MotionEvent,
        v: Float,
        v1: Float
    ): Boolean {
        return false
    }

    /**
     * 时机2：滑动手势停止
     *
     * @param motionEvent
     * @param motionEvent1
     * @param v
     * @param v1
     * @return
     */
    override fun onFling(
        motionEvent: MotionEvent,
        motionEvent1: MotionEvent,
        v: Float,
        v1: Float
    ): Boolean {
        isHasLayout = false
        postDelay {
            KKExposurePageManager.getExposureManager(this)?.triggerViewCalculate(
                TRIGGER_VIEW_CHANGED,
                this@KKTrackerExposureLayout,
                isVisible = true,
                clearAll = false,
                lastVisibleViewMap = lastVisibleViewMap
            )
        }
        return false
    }

    /**
     * 其他时机：
     * 时机3：通过home切换前后台dispatchWindowFocusChanged
     * 时机4：进入其他页面
     * 时机5：window
     * @param hasFocus
     */
    override fun dispatchWindowFocusChanged(hasFocus: Boolean) {
        if (isHasLayout) {
            return super.dispatchWindowFocusChanged(hasFocus)
        }
        val time = System.currentTimeMillis()
        if (time - lastOnWindowFocusChangedSystemTimeMillis > 500) {
            isHasLayout = false
            ViewExposureLog.d("==== dispatchWindowFocusChanged $hasFocus")
            lastOnWindowFocusChangedSystemTimeMillis = time
            KKExposurePageManager.getExposureManager(this)?.triggerViewCalculate(
            TRIGGER_WINDOW_CHANGED,
            this,
            true,
            hasFocus, lastVisibleViewMap)
        }
        super.dispatchWindowFocusChanged(hasFocus)
    }

    /**
     * view显示状态改变
     * @param changedView View
     * @param visibility Int
     */
    override fun dispatchVisibilityChanged(changedView: View, visibility: Int) {
        val time = System.currentTimeMillis()
        if (time - lastOnVisibilityChangedSystemTimeMillis > 500) {
            ViewExposureLog.d("==== dispatchVisibilityChanged $visibility")
            isHasLayout = false
            lastOnVisibilityChangedSystemTimeMillis = time
//        KKExposureManager.getInstance().trdispatchVisibilityChangediggerViewCalculate(
//            TRIGGER_WINDOW_CHANGED,
//            this,
//            visibility == View.VISIBLE,
//            true,
//            lastVisibleViewMap = lastVisibleViewMap
//        )
        }
        super.dispatchVisibilityChanged(changedView, visibility)
    }

    /**
     * postdelay统一封装
     */
    private fun postDelay(delayTime: Long = 500L, block: () -> Unit) {
        postDelayed({
            block()
        }, delayTime)
    }

    companion object {
        private const val CLICK_LIMIT = 20f
    }
}